//
// Created by v on 2019/11/8 上午10:40.
// Copyright (c) 2019 jmdvirus All rights reserved.
//
//     ******          *             *--*
//       ||            *             |
//       ||  *--*--*---*  * *-********--*
//   *  //   *  *  *   *\ / ||  |  |    |
//    **    *  *  *---* *  *   *--* *--*
//

#include <pthread.h>
#include <sys/prctl.h>
#include <unistd.h>

#include "CMMsgTaskManager.h"

void *msg_task_manager_run_thread(void *args)
{
    prctl(PR_SET_NAME, __func__);
    CMMsgTaskManager *msgTaskManager = (CMMsgTaskManager *)args;

    msgTaskManager->m_exit = false;
    while (!msgTaskManager->m_exit)
    {
        if (msgTaskManager->m_tasks.empty())
        {
            usleep(50000);
            continue;
        }
        msgTaskManager->m_lock.lock(__func__, __LINE__);
        for (auto iter : msgTaskManager->m_tasks)
        {
            CMMsgTaskInfo *msgTaskInfo = iter.second;
            if (msgTaskInfo->m_callers.empty() ||
                msgTaskInfo->m_cmdList.empty())
            {
                continue;
            }
            std::vector<CMMsgTaskInfo::CMMsgCmdList>::iterator xiter =
                msgTaskInfo->m_cmdList.begin();
            while (xiter != msgTaskInfo->m_cmdList.end())
            {
                for (auto iter : msgTaskInfo->m_callers)
                {
                    iter->handler(xiter->m_cmd, xiter->m_args, xiter->m_data);
                }
                xiter = msgTaskInfo->m_cmdList.erase(xiter);
            }
        }
        msgTaskManager->m_lock.unlock();
        usleep(50000);
    }
    return NULL;
}

int CMMsgTaskManager::Init()
{
    pthread_t pid;
    int ret = pthread_create(&pid, NULL, msg_task_manager_run_thread, this);
    pthread_detach(pid);
    return ret;
}

void CMMsgTaskManager::Deinit()
{
    m_lock.lock(__func__, __LINE__);
    m_exit = true;
    m_lock.unlock();
    Clear();
}

void CMMsgTaskManager::Clear()
{
    m_lock.lock(__func__, __LINE__);
    for (auto &i : m_tasks)
    {
        delete i.second;
    }
    m_tasks.clear();
    m_lock.unlock();
}

int CMMsgTaskManager::AddMsg(CMMsgTaskInfo *msgTaskInfo, int cmd, char *args,
                             void *data)
{
    if (!msgTaskInfo)
        return -1;
    CMMsgTaskInfo::CMMsgCmdList cmdList;
    cmdList.m_args = args;
    cmdList.m_cmd  = cmd;
    cmdList.m_data = data;
    msgTaskInfo->m_cmdList.push_back(cmdList);
    return msgTaskInfo->m_cmdList.size();
}

int CMMsgTaskManager::AddNew(const char *name, CMMsgTaskInterface *caller)
{
    if (!name || !caller)
        return -1;
    CMMsgTaskInfo *info = new CMMsgTaskInfo();
    info->m_name        = name;
    info->m_callers.push_back(caller);
    m_tasks[name] = info;
    return info->m_callers.size();
}

int CMMsgTaskManager::Register(const char *name, CMMsgTaskInterface *caller)
{
    if (!name || !caller)
        return -1;
    m_lock.lock(__func__, __LINE__);
    int            ret         = 0;
    CMMsgTaskInfo *msgTaskInfo = m_tasks[name];
    if (msgTaskInfo)
    {
        msgTaskInfo->m_callers.push_back(caller);
        ret = msgTaskInfo->m_callers.size();
    }
    else
    {
        ret = AddNew(name, caller);
    }
    m_lock.unlock();
    return ret;
}

int CMMsgTaskManager::Unregister(const char *name, CMMsgTaskInterface *caller)
{
    if (!name || !caller)
        return -1;
    m_lock.lock(__func__, __LINE__);
    int            ret         = 0;
    CMMsgTaskInfo *msgTaskInfo = m_tasks[name];
    if (msgTaskInfo)
    {
        std::list<CMMsgTaskInterface *>::iterator iter =
            msgTaskInfo->m_callers.begin();
        while (iter != msgTaskInfo->m_callers.end())
        {
            if (*iter == caller)
            {
                msgTaskInfo->m_callers.erase(iter);
            }
            iter++;
        }
        ret = msgTaskInfo->m_callers.size();
    }
    m_lock.unlock();
    return ret;
}

int CMMsgTaskManager::Send(const char *name, int cmd, char *args, void *data)
{
    if (!name)
        return -1;
    m_lock.lock(__func__, __LINE__);
    auto iter = m_tasks.find(name);
    if (iter == m_tasks.end())
    {
        m_lock.unlock();
        return -2;
    }
    AddMsg(iter->second, cmd, args, data);

    m_lock.unlock();
    return 0;
}
